package com.xd.util;

import CalaGaussDistribution.*;
import com.xd.model.CandidatePoint;
import com.mathworks.toolbox.javabuilder.*;

import java.util.HashMap;
import java.util.LinkedList;

/**
 * designed by Matt
 *
 * @author Matt
 *         e-mail:ZHUHAN1401@126.com
 * @version JDK 1.8.0_101
 * @since 2017/6/10 13:03 星期六
 * Description: description
 */
public class CommonCalculationUtil {

    /**
     * 正态分布计算，调用MATLAB代码
     *
     * @param distance
     * @return
     */
    public static Double GaussDistribution(Float distance) {
        Double gaussDis = null;
        try {
            calaGaussDis calaGaussDis = new calaGaussDis();
            Object[] result = calaGaussDis.GaussDistribution(1, distance);
            gaussDis = Double.valueOf(result[0].toString());
        } catch (MWException e) {
            e.printStackTrace();
        }
        return gaussDis;
    }

    /**
     * 计算余弦距离
     *
     * @param Type
     * @param averageSpeed
     * @return
     */
    public static Double cosineDistance(LinkedList<String> Type, Double averageSpeed) {
        LinkedList<Double> speed=tranfTypeToSpeed(Type);
        Double speedContimeaver = 0d;
        Double sqarOfConsSpeed = 0d, sqarOfAverSpeed = 0d;
        for (Double consSpeed : speed) {
            speedContimeaver += consSpeed * averageSpeed;
            sqarOfConsSpeed += Math.pow(consSpeed, 2);
            sqarOfAverSpeed += Math.pow(averageSpeed, 2);
        }
        return speedContimeaver / (Math.sqrt(sqarOfConsSpeed) * Math.sqrt(sqarOfAverSpeed));
    }

    /**
     * 根据类型近似求解特征速度
     *
     * @param Type
     * @return
     */
    public static LinkedList<Double> tranfTypeToSpeed(LinkedList<String> Type) {
        LinkedList<Double> speed = new LinkedList<Double>();
        for (String s : Type) {
            if (s.equals("residential")) {
                speed.add(6.94d);
            } else if (s.equals("secondary")) {
                speed.add(11.11d);
            } else if (s.equals("tertiary")){
                speed.add(9.72d);
            }else {
                speed.add(9.25d);
            }
        }
        return speed;
    }

    /**
     * 根据X Y坐标计算两点距离
     *
     * @param x1
     * @param x2
     * @param y1
     * @param y2
     * @return
     */
    public static Double calaDistanceInNearXY(Integer x1, Integer x2, Integer y1, Integer y2) {
        return Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
    }

    /**
     * 找最大值
     *
     * @param STValues
     * @return
     */
    public static Double findMaxVal(LinkedList<Double> STValues) {
        Double max = STValues.get(0);
        for (Double val : STValues) {
            if (val > max) {
                max = val;
            }
        }
        return max;
    }

    /**
     * 在HashMap中寻找最大值
     *
     * @param STValuesMap
     * @return
     */
    public static CandidatePoint findMaxVal(HashMap<CandidatePoint, Double> STValuesMap) {
        Double maxVal = -2147483647d;
        CandidatePoint maxPoint = null;
        for (CandidatePoint candidatePoint : STValuesMap.keySet()) {
            if (STValuesMap.get(candidatePoint) > maxVal) {
                maxPoint = candidatePoint;
                maxVal = STValuesMap.get(candidatePoint);
            }
        }
        return maxPoint;
    }


    /*
    public LinkedList<CandidatePoint> resultMatching(LinkedList<GPSPoint> GPSPoints, LinkedList<LinkedList<CandidateEdge>> candidateEdgeGraph) {
        // 初始化STValuesa,为第一个GPS点的候选点C赋值
        GPSPoint firstPoint = GPSPoints.getFirst();
        HashMap<CandidatePoint, Double> firstSTValues = new HashMap<CandidatePoint, Double>();
        for (CandidatePoint candidatePoint : firstPoint.getCandidatePoints()) {
            firstSTValues.put(candidatePoint, candidatePoint.getGaussDistribution());
        }
        firstPoint.setPointsSTValues(firstSTValues);

        // 计算后续点的f值
        for (Integer i = 1; i < GPSPoints.size(); i++) {
            GPSPoint gpsPoint = GPSPoints.get(i);
            HashMap<CandidatePoint, Double> STValuesMap = new HashMap<CandidatePoint, Double>();
            // 处理一个GPS点的候选点
            for (CandidatePoint candidatePoint : gpsPoint.getCandidatePoints()) {
                //从Graph中取出指向该候选点的候选边
                LinkedList<CandidateEdge> edges = candidateEdgeGraph.get(i + 1);
                LinkedList<Double> STValTemp = new LinkedList<Double>();
                for (CandidateEdge candidateEdge : edges) {
                    if (candidateEdge.geteEnd() == candidatePoint) {
                        Double gaussDis = candidateEdge.geteStart().getGaussDistribution();
                        Double TransPro = candidateEdge.getTransPro();
                        Double TemporalVal = candidateEdge.getTemporalValue();
                        Double STValue = gaussDis * TransPro * TemporalVal;
                        STValTemp.add(STValue);
                    }
                }
                Double finalSTVal = CommonCalculationUtil.findMaxVal(STValTemp);
                STValuesMap.put(candidatePoint, finalSTVal);
            }
            gpsPoint.setPointsSTValues(STValuesMap);

        }

        //找出最大值路径
        LinkedList<CandidatePoint> finalPath = new LinkedList<CandidatePoint>();
        for (GPSPoint gpsPoint : GPSPoints) {
            finalPath.add(CommonCalculationUtil.findMaxVal(gpsPoint.getPointsSTValues()));
        }
        return finalPath;
    }


     /**
     * 根据GPSPoints创建图，并计算转移概率、平均速度、时间分析值（即余弦距离）
     *
     * @param gpsPoints
     * @return
     *//*
    public LinkedList<LinkedList<CandidateEdge>> constructEdgeGraph(LinkedList<GPSPoint> gpsPoints) {
        LinkedList<LinkedList<CandidateEdge>> candidateEdgeGraph = new LinkedList<LinkedList<CandidateEdge>>();
        //添加空白头节点
        candidateEdgeGraph.add(null);

        for (Integer i = 0; i < gpsPoints.size() - 1; i++) {
            GPSPoint p1 = gpsPoints.get(i);
            GPSPoint p2 = gpsPoints.get(i + 1);

            Double distOfP = DistanceUtil.calculateDistance(p1, p2);
            Long timeInterval = p1.getpTime().getTime() - p2.getpTime().getTime();
            LinkedList<CandidateEdge> edges = new LinkedList<CandidateEdge>();

            for (CandidatePoint candidatePointA : p1.getCandidatePoints()) {
                for (CandidatePoint candidatePointB : p2.getCandidatePoints()) {
                    CandidateEdge edge = new CandidateEdge(candidatePointA, candidatePointB);

                    Double shortestLength = DistanceUtil.calcShortestLengthOfPath(candidatePointA, candidatePointB);
                    Double averageSpeed = shortestLength / timeInterval;
                    LinkedList<Double> speed = DistanceUtil.getSpeedConstraints(candidatePointA, candidatePointB);
                    edge.setTransPro(distOfP / shortestLength);
                    edge.setTemporalValue(CommonCalculationUtil.cosineDistance(speed, averageSpeed));

                    edges.add(edge);
                }
            }
            candidateEdgeGraph.add(edges);
        }
        return candidateEdgeGraph;
    }*/



}
